
/************************************************************************************************
*   深圳市摩西尔电子有限公司 @版本所有@
*
*   此文件用于测试界面树型控件
*
* 修改:
*   1. 类型 : 创建
*      作者 : 巫昭雯
*      时间 : 2021.04.20
*      内容 : 所有代码
************************************************************************************************/


/* global layui */
layui.define(["layer", "tree"], function (exports) {
    var $ = layui.jquery;
    var layer = layui.layer;
    var tree = layui.tree;
    // 定义执行状态对象
    var o_Status = {
        0: "失败",
        1: "成功",
        2: "加载脚本失败",
        3: "注册的测试用例函数不存在",
        4: "测试用例内部报错"
    };

    // 保存结果
    var m_o_save_res = [];

    // 定义ui组件树
    var o_cop_tree = {
        el_info: "",
        render: ct_render,
        click: function (o) {
            // console.log(o);
            if (-1 !== o.data.field) {
                // 显示测试用例信息
                ct_show_testcase_info(m_o_save_res[o.data.id]);

                // selectd style
                this.elem.find(".selected").removeClass("selected");
                o.elem.find(".layui-tree-txt").addClass("selected");
            }
        },
        keyboard_operation: function (e) {
            var ev = e || window.event;

            if (ev.altKey || ev.ctrlKey || ev.shiftKey || ev.metaKey) {
                return;
            }

            if (38 === ev.which || 40 === ev.which) {
                ct_switch_show_info(o_cop_tree.tree_ins.config.elem.selector, ev.which);
                return;
            }
        },
        operate: function (obj) { //eslint-disable-line
            // console.log("修改",obj);
        },
        // 展开
        foldAll: function (params) { //eslint-disable-line
            ct_expand_and_collapse(o_cop_tree.tree_ins.config.elem[0].id, false);
        },
        // 折叠
        expandAll: function (params) { //eslint-disable-line
            ct_expand_and_collapse(o_cop_tree.tree_ins.config.elem[0].id, true);
        },
        run_selected: ct_run_selected,
        run_selected_async: ct_run_selected_async,
        done: function () {},
        error: ct_catch_error
    };

    var o_pos = function (i, j) { //eslint-disable-line
        this.i = i;
        this.j = j;
    };


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    循环执行单个测试用例; 逐步操作; 执行一条返回结果再执行第二条;
     * 参数:
     *    NA
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-05-13
     *       内容 : 所有代码
    ************************************************************************************************/
    var m_o_ct_loop_run = {
        UI_I: 0,
        UI_J: 0,
        ARR_DATA: [],
        // @param { Promise<Object> } 选中的单条数据对象
        run: function (obj) {
            if ("object" !== typeof obj || "undefined" === typeof obj.id ) {
                return;
            }

            ct_before_run(obj);
            ct_run_test_case(obj.id, obj, function (ui_id, code, resInfo) {
                ct_run_result_callback(ui_id, code, resInfo);
                m_o_ct_loop_run.next();
            });
            return;
        },
        next: function () {
            this.add_j();
        },
        add_i: function () {
            this.UI_I++;
            this.UI_J = 0;
            var obj = 0;

            try {
                obj = this.ARR_DATA[this.UI_I].children[this.UI_J];
            } catch (error) {
                // done
                o_cop_tree.done("run_selected_async");
                return;
            }

            if ("object" === typeof obj ) {
                this.run(obj);
            }
        },
        add_j: function () {
            this.UI_J++;

            if (!this.ARR_DATA[this.UI_I]) {
                o_cop_tree.done("run_selected_async");
                return;
            }

            var obj = this.ARR_DATA[this.UI_I].children[this.UI_J];

            if ("object" === typeof obj) {
                this.run(obj);
            } else {
                this.add_i();
            }
        },
        // @param { Promise<Array> } a_data 选中的树型数据
        init: function (a_data) {
            this.UI_I = 0;
            this.UI_J = 0;

            if ("object" === typeof a_data && a_data.constructor === Array) {
                this.ARR_DATA = a_data;
                this.run(this.ARR_DATA[0].children[0]);
            }
        },
        error: function (err) {
            if (this.ARR_DATA[this.UI_I]) {
                var obj = this.ARR_DATA[this.UI_I].children[this.UI_J];

                ct_run_result_callback(obj.id, 4, err);
                m_o_ct_loop_run.next();
            }
        }
    };

    // catch error
    function ct_catch_error(msg) {
        m_o_ct_loop_run.error(msg);
    }

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    渲染树型数据方法
     * 参数:
     *    @param { Promise<String> } params 外部传参; 与树型原 render 方法传参一致
     * 返回:
     *    @returns { Promise<Boolean> } false === 参数格式错误 || 参数没有date 属性 || 没有url属性
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-21
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_render(params) {
        if ("object" !== typeof params) {
            return false;
        }

        var data = params.data;

        if (data && "object" === typeof data && data.construct === Array) {
            ct_init(params, data);
            return true;
        }

        var url = params.url;

        if ("string" === typeof url && url.trim()) {
            $.getJSON(url, function (res) {
                res = ct_deal_json_to_data(res);
                if (res) {
                    ct_init(params, res);
                }
            });
            return true;
        }

        return false;
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    初始化函数
     * 参数:
     *    @param { Promise<Object> } param 与render传参一致
     *    @param { Promise<Array> } data 树型数据数组 (param 参数的data属性)
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-21
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_init(param, data) {
        // 重写参数
        param.url = undefined; //eslint-disable-line
        param.data = data;
        param.click = o_cop_tree.click;
        param.operate = o_cop_tree.operate;
        o_cop_tree.el_info = param.elemInfo;
        o_cop_tree.done = param.done || function () {};

        // 渲染表格
        o_cop_tree.tree_ins = tree.render(param);
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    展开折叠;
     * 参数:
     *    @param { Promise<String> } el_id 树型容器id
     *    @param { Promise<Boolean> } b  true === 展开 || false === 折叠
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-21
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_expand_and_collapse(el_id, b) {
        // layui-tree-setHide
        // layui-tree-pack
        $("#" + el_id + " .layui-tree-pack").each(function (i, ele) {
            ct_single_block_switch_collapse($(ele).parent(".layui-tree-setHide"), b);
        });
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    单个节点块切换折叠
     * 参数:
     *    @param { Promise<Object> } $_el 父级块节点;(目录节点) 包含类 layui-tree-setHide 的节点
     *    @param { Promise<Number> } b true === 展开 || false === 折叠
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-05-12
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_single_block_switch_collapse($_el, b) {
        // .layui-tree-pack
        if (0 >= $_el.length || "function" !== typeof $_el.children) {
            return;
        }

        var $_this = $_el.children(".layui-tree-pack");

        if (0 >= $_this.length) {
            return;
        }

        if (b && "block" !== $_this[0].style.display) {
            // el_menu
            $_this.parent(".layui-tree-setHide").addClass("layui-tree-spread");
            // el_icon
            $_this.prev().find(".layui-tree-iconClick").children().removeClass("layui-icon-addition").addClass("layui-icon-subtraction");
            $_this.slideDown();
        }

        if (!b && "block" === $_this[0].style.display) {
            // el_menu
            $_this.parent(".layui-tree-setHide").removeClass("layui-tree-spread");
            // el_icon
            $_this.prev().find(".layui-tree-iconClick").children().removeClass("layui-icon-subtraction").addClass("layui-icon-addition");
            $_this.slideUp();
        }
    }


    // 执行选中逐行; @param { Promise<String> } id 表格id 唯一标识;
    function ct_run_selected_async(id) {
        var a_check_data = tree.getChecked(id);
        var ui_len_check = a_check_data.length;

        if (0 >= ui_len_check) {
            layer.alert("未选中任何东西");
            o_cop_tree.done("run_selected_async");
            return false;
        }

        m_o_ct_loop_run.init(a_check_data);
        return true;
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    执行结果回调函数
     * 参数:
     *    @param { Promise<String> } ui_id 表格数据下标
     *    @param { Promise<String> } code 结果返回状态码
     *    @param { Promise<String> } resInfo 执行结果msg
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-05-13
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_run_result_callback(ui_id, code, resInfo) {
        resInfo = resInfo || "";
        var statusVal = o_Status[code] || "其他错误";
        // var showVal = statusVal + resInfo;

        if (ct_util_is_object_dom(resInfo)) {
            m_o_save_res[ui_id].resultEl = resInfo;
        }

        m_o_save_res[ui_id].resultCode = statusVal;
        m_o_save_res[ui_id].resultInfo = resInfo;

        if (Number($(".t_info").attr("data-id")) === Number(ui_id)) {
            ct_show_testcase_info(m_o_save_res[ui_id]);
        }
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    执行选中节点
     * 参数:
     *    @param { Promise<String> } id 表格id 唯一标识;
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-21
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_run_selected(id) {
        //获得选中的节点
        // console.log(tree.getChecked(id));
        var a_check_data = tree.getChecked(id);
        var ui_len_check = a_check_data.length;

        if (0 >= ui_len_check) {
            layer.alert("未选中任何东西");
            return;
        }

        var a_child = [];
        var ui_len_child = 0;

        for (var i = 0; i < ui_len_check; i++) {
            var o_i = a_check_data[i];

            if ((a_child = o_i.children) && (ui_len_child = a_child.length) ) {
                for (var j = 0; j < ui_len_child; j++) {
                    var o_j = a_child[j];

                    ct_before_run(o_j);
                    ct_run_test_case(o_j.id, o_j, ct_run_result_callback);
                }
            }
        }
    }


    function ct_util_is_object_dom(obj) {
        if ("object" === typeof HTMLElement) {
            return obj instanceof HTMLElement;
        }

        if (obj) {
            return "object" === typeof obj && 1 === obj.nodeType && "string" === typeof obj.nodeName;
        }

        return false;
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    运行用例单个;
     * 参数:
     *    @param { Promise<Number> } iData 表格数据下标
     *    @param { Promise<Object> } oData 表格一行数据对象
     *    @param { Promise<Function> } callback
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    callback(iData, code, msg);
     *    iData: 参数园路返回
     *    code: 执行当前表格的错误码; oStatus 定义
     *    msg: 测试用例返回的结果说明;
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-19
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_run_test_case(iData, oData, callback) {
        if ("string" === typeof oData.url && oData.url.trim()) {
            loadScript(run);
            return;
        }

        run();

        /************************************************************************************************
         * 类型:
         *    内置函数
         * 功能:
         *    内置执行函数; 跳转注册的测试用例并执行
         * 参数:
         *    @param { Promise<String> } err 错误码; 只有错误码 === 2 时直接返回; 不执行绑定的测试用例
         * 返回:
         *    NA
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2021-04-19
         *       内容 : 所有代码
        ************************************************************************************************/
        function run(err) {
            if (2 === err) {
                callback(iData, 2);
                return;
            }

            var fnName = oData.fn;
            var fn = null;

            if ( fnName && (fn = parent[fnName]) ) {
                try {
                    fn(function tc_result_callback(code, msg) {
                        callback(iData, code, msg);
                        return;
                    });
                } catch (error) {
                    console.error(error);  // eslint-disable-line
                    callback(iData, 4, error.message);
                }
                return;
            }

            callback(iData, 3);
            return;
        }


        /************************************************************************************************
         * 类型:
         *    函数
         * 功能:
         *    加载脚本
         * 参数:
         *    @param { Promise<Function> } cb 回调函数
         * 返回:
         *    NA
         * 例子:
         *    NA
         * 备注:
         *    NA
         * 修改:
         *    1. 类型 : 创建
         *       作者 : 巫昭雯
         *       时间 : 2021-04-19
         *       内容 : 所有代码
        ************************************************************************************************/
        function loadScript(cb) {
            // cbFn === callback function
            var cbFn = cb || function () {};
            var script = document.createElement("script");

            script.type = "text/javascript";
            script.src = oData.url;
            script.defer = true;
            script.async = false;

            if (script.readyState) {
                //IE
                script.onreadystatechange = function () {
                    if ("loaded" === script.readyState || "complete" === script.readyState) {
                        script.onreadystatechange = null;
                        cbFn();
                    }
                };
            } else {
                //其他浏览器
                script.onload = function () {
                    cbFn();
                };

                script.onerror = function name(err) {
                    cbFn(2, err);
                };
            }

            try {
                document.getElementsByTagName("head")[0].appendChild(script);
                // throw Error();
            } catch (error) {
                cbFn(2);
            }
        }
    }


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    显示用例信息
     * 参数:
     *    @param { Promise<String> } obj 单条用例对象数据
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-21
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_show_testcase_info(obj) {
        if ("object" !== typeof obj && obj.id) {
            return;
        }

        var str_res_code = obj.resultCode.trim();
        var str_res = (o_Status[1] !== str_res_code && "--" !== str_res_code && -1 === str_res_code.indexOf("layui-icon-loading")) ? "<span class='error'>" + str_res_code + "</span>" : "<span>" + str_res_code + "</span>";

        var s_info = "<div class='t_info' data-id=" + obj.id + ">" +
        "<p><span class='title'>用例名称</span> <span>" + obj.title + "</span></p>" +
        "<p><span class='title'>用例说明</span> <span>" + obj.descript + "</span></p>" +
        "<p><span class='title'>执行结果</span> " + str_res + "</p>" +
        "<p><span class='title'>结果说明</span> <span>" + obj.resultInfo + "</span></p>" +
        "</div>";

        var s_wrap_html = "<fieldset class='layui-elem-field layui-field-title layui-border-cyan'><legend>用例信息</legend>" + s_info + "</fieldset>";

        $(o_cop_tree.el_info).html(s_wrap_html);

        if ("undefined" !== typeof obj.resultEl) {
            $(o_cop_tree.el_info + " .t_info").append(obj.resultEl);
        }
    }

    function ct_get_run_animate() {
        return "<i class='layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop'></i>";
    }

    // 执行用例之前; 添加执行动画
    function ct_before_run(obj) {
        if ("object" !== typeof obj || "undefined" === typeof obj.id ) {
            return;
        }

        m_o_save_res[obj.id].resultCode = ct_get_run_animate();
        m_o_save_res[obj.id].resultInfo = ct_get_run_animate();

        if (Number($(".t_info").attr("data-id")) === Number(obj.id)) {
            ct_show_testcase_info(m_o_save_res[obj.id]);
        }
    }

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *   方向键移动切换显示信息
     * 参数:
     *    @param { Promise<Object> } el 树型控件容器选择器
     *    @param { Promise<Number> } dir 方向 键盘事件 which值
     * 返回:
     *    NA
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-05-12
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_switch_show_info(el, dir) {
        if (!dir || !el) {
            return;
        }

        // current selected text class === layui-tree-set
        var $_selected_node = $(el + " " + ".layui-tree-txt.selected");

        if (0 >= $_selected_node.length) {
            return;
        }

        // data-id symbols
        var $_parent = $_selected_node.parents("[data-id]");
        var $_parent_node = $_parent.eq(0);
        var $_parent_block = $_parent.eq(1);
        var ui_node_id = Number($_parent_node.attr("data-id"));

        if ("object" !== typeof m_o_save_res[ui_node_id]) {
            return;
        }

        // switch selected text
        var $_selected_switch = null;

        if (38 === dir) {
            // 选择上一个
            $_selected_switch = $_parent_node.prev();

            if (!$_selected_switch.length) {
                // 上一个目录快
                var $_block_pre = $_parent_block.prev();

                if ($_parent_block.length && $_block_pre.length) {
                    var $_block_pre_chi = $_block_pre.find("[data-id]");

                    $_selected_switch = $_block_pre_chi.eq($_block_pre_chi.length - 1);

                    ct_single_block_switch_collapse($_block_pre, true);
                }
            }
        }

        if (40 === dir) {
            // 选择下一个
            $_selected_switch = $_parent_node.next();

            if (!$_selected_switch.length) {
                // 下一个目录块
                var $_block_next = $_parent_block.next();

                if ($_parent_block.length && $_block_next.length) {
                    var $_block_next_chi = $_block_next.find("[data-id]");

                    $_selected_switch = $_block_next_chi.eq(0);

                    ct_single_block_switch_collapse($_block_next, true);
                }
            }
        }

        if ($_selected_switch.length) {
            $_selected_switch.find(".layui-tree-txt").click();
        }

        return;
    }

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    处理请求到的json数据格式转化为树型结构数据格式
     * 参数:
     *    @param { Promise<Object> } json 请求的数据对象
     * 返回:
     *    @returns { Promise<Boolean> } fasle === 参数类型错误
     * 例子:
     *    NA
     * 备注:
     *    resultEl === 返回结果的dom对象; 当某些测试用例需要返回dom对象
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2021-04-21
     *       内容 : 所有代码
    ************************************************************************************************/
    function ct_deal_json_to_data(json) {
        if ("object" !== typeof json) {
            return false;
        }

        var a_data = [];
        var a_keys = Object.keys(json);
        var ui_len_i = a_keys.length;
        var id = 0;

        for (var i = 0; i < ui_len_i; i++) {
            var a_j = json[a_keys[i]];
            var ui_len_j = a_j.length;

            // 菜单
            id++;
            var p_id = id;
            var a_chi = [];

            a_data.push({
                "id": p_id,
                "title": a_keys[i],
                "field": -1,
                "length": ui_len_j,
                "children": a_chi
            });

            // 测试用例
            for (var j = 0; j < ui_len_j; j++) {
                var item = a_j[j];

                id++;
                a_chi.push({
                    "id": id,
                    "title": "<span title='" + item.descript + "'>" + item.name + "</span>",
                    "field": p_id,
                    "descript": item.descript,
                    "fn": item.fn,
                    "url": item.url,
                    "resultCode": "--",
                    "resultInfo": "--",
                    "resultEl": null,
                    "operation": ""
                });

                m_o_save_res[id] = {
                    "id": id,
                    "title": item.name,
                    "field": p_id,
                    "descript": item.descript,
                    "fn": item.fn,
                    "url": item.url,
                    "resultCode": "--",
                    "resultInfo": "--",
                    "resultEl": null,
                    "operation": ""
                };
            }
        }

        return a_data;
    }

    exports("cop_tree", o_cop_tree);
});


